somaxconn、 tcp_max_syn_backlog 和 tcp_backlog 对 redis 性能的影响

momo314相同方式共享非商业用途署名转载

最近我们的 api 经常会在高峰期出现下面的两个错误,两个错误都是在连接 redis 的时候出现的(连接 redis 使用的类库是 CSRedisCore)。

异常1:

Connection was not opened

异常2:

【10.0.0.8:6379/0】状态不可用,等待后台检查程序恢复方可使用。Connect to server timeout

高峰期 redis 的 instantaneous_ops_per_sec 大概可以达到 300,000 左右; 而 connected_clients 大概可以达到 2,000 左右。

经过一段时间的排查,始终没有什么头绪。经过各种优化之后有所缓解,但始终无法根治。后来开始怀疑是 redis 的配置有关,于是开始逐项排查。


一、 排查可疑配置项

可疑配置项一

# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 511

可疑配置项二

docker run --sysctl net.core.somaxconn=1024

我们的 redis 是运行在 docker 容器中的


tcp-backlog, 默认值为 511。按照 redis.conf 的注释来看,在高访问量的环境下,需要适当的调大这个值。且此值与系统内核的 somaxconntcp_max_syn_backlog 配置有关。

那么,somaxconntcp_max_syn_backlog 分别代表什么意思呢?

linux 会维护两个队列,未连接队列已连接队列,一个TCP连接首先会进入未连接队列,在完成3次握手成功之后则会进入已连接队列。而应用程序会从已连接队列中取出连接,并进行响应。

所以,上述 redis.conf 配置文件中的 tcp-backlog 配置,实际上是对已连接队列的大小限制。

未连接队列已连接队列,在系统内核中又对应着 /etc/sysctl.conf 中的两个配置项:

  1. 未连接队列(TCP层)

    • 对应配置:net.ipv4.tcp_max_syn_backlog
    • Ubuntu 18.04 下默认值为 256

      # 查看 tcp_max_syn_backlog
      cat /proc/sys/net/ipv4/tcp_max_syn_backlog
      
  2. 已连接队列(应用层)

    • 对应配置:net.core.somaxconn
    • Ubuntu 18.04 下默认值为 128

      # 查看 somaxconn
      cat /proc/sys/net/core/somaxconn
      

综上所述:

  • 如果应用程序处理不及时,则会导致已连接队列(somaxconn)堆积。
  • 若已连接队列已满,会造成连接在3次握手完成后仍然无法进入已连接队列,最终导致未连接队列也被占满。
  • 如果未连接队列(tcp_max_syn_backlog)已满,则新连接将一直处于等待ACK的状态,最终导致超时。
  • redis.conf 的 tcp-backlog 配置 和 内核的 somaxconn 配置 如果不相同,则实际效果为两者中的较小值。

二、 修改内核配置 tcp_max_syn_backlog 与 somaxconn

要修改这两个值,并永久生效,我们可以直接将配置项加入到 /etc/sysctl.conf 文件:

# file: /etc/sysctl.conf
net.ipv4.tcp_max_syn_backlog = 4096
net.core.somaxconn = 4096

然后执行一下命令,使修改生效:

sudo sysctl -p

三、 修改 redis 配置 tcp-backlog

# file: redis.conf

# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 4096

四、 修改 docker run 参数,并使用新的配置重新创建 docker 容器

docker run --sysctl net.core.somaxconn=4096 --sysctl net.ipv4.tcp_max_syn_backlog=4096
✎﹏ 本文来自于 momo314和他们家的猫,文章原创,转载请注明作者并保留原文链接。